
define( "charoite/store",
    ["dojo/_base/xhr", "dojo/json", "dojo/_base/declare", "dojo/store/util/QueryResults", "charoite/jsonrest"],
    function(xhr, JSON, declare, QueryResults, JsonRest) {

    //  module:
    //    charoite/store
    //  summary:
    //    The module defines a JSON/REST based object store
    return declare("charoite.store", null, {

        // summary:
        //		This is a store for RESTful communicating with a server through JSON
        //		formatted data. It implements dojo.store.api.Store.

        constructor: function(/*charoite.store.JsonRest*/ options){
            // summary:
            //		This is a basic store for RESTful communicating with a server through JSON
            //		formatted data.
            // options:
            //		This provides any configuration information that will be mixed into the store
            declare.safeMixin(this, options);
            this.rest = new JsonRest();
        },

        // target: String
        //	The target base URL to use for all requests to the server. This string will be
        // 	prepended to the id to generate the URL (relative or absolute) for requests
        // 	sent to the server
        target: "",


        idProperty: "id",
        typeProperty: "type",
        captionProperty: 'caption',
        childrenProperty: 'items',


        // sortParam: String
        // 		The query parameter to used for holding sort information. If this is omitted, than
        //		the sort information is included in a functional query token to avoid colliding
        // 		with the set of name/value pairs.

        append_item: function(context, parent, item)
        {
            var child = {};
            child.data = item;
            child.parent = parent;
            child.caption = item[context.captionProperty];
            child.id = parent.id + "/" + item[context.idProperty];
            parent.items.push(child);
            return child;
        },

        get: function(id, options)
        {
            return this.rest.get(this.target + id, options);
        },

        getIdentity: function(object)
        {
            return object.id;
        },

        put: function(object, options)
        {
            options = options || {};
            var id = ("id" in options) ? options.id : object.id;
            if((typeof id != "undefined") && !options.incremental)
            {
                return this.rest.put(options.url, object, options);
            }
            return this.rest.post(options.url, object, options);
        },

        add: function(object, options)
        {
            options = options || {};
            options.overwrite = false;
            options.url = this.target + options.parent.id;
            var context = this;
            this.put(object, options).then(function(dataObject)
            {
                var child = context.append_item(context, options.parent, dataObject);
                context.onChildrenChange(options.parent, options.parent.items);
                context.onChange(child);
            }, this.onError);
        },

        remove: function(id){
            // summary:
            //		Deletes an object by its identity. This will trigger a DELETE request to the server.
            // id: Number
            //		The identity to use to delete the object
            return xhr("DELETE",{
                url:this.target + id
            });
        },

        query: function(query, options){
            // summary:
            //		Queries the store for objects. This will trigger a GET request to the server, with the
            //		query added as a query string.
            // query: Object
            //		The query to use for retrieving objects from the store.
            //	options: dojo.store.api.Store.QueryOptions?
            //		The optional arguments to apply to the resultset.
            //	returns: dojo.store.api.Store.QueryResults
            //		The results of the query, extended with iterative methods.
            var headers = {Accept: this.accepts};
            options = options || {};

            if(options.start >= 0 || options.count >= 0){
                headers.Range = "items=" + (options.start || '0') + '-' +
                    (("count" in options && options.count != Infinity) ?
                        (options.count + (options.start || 0) - 1) : '');
            }
            if(query && typeof query == "object"){
                query = xhr.objectToQuery(query);
                query = query ? "?" + query: "";
            }
            if(options && options.sort){
                var sortParam = this.sortParam;
                query += (query ? "&" : "?") + (sortParam ? sortParam + '=' : "sort(");
                for(var i = 0; i<options.sort.length; i++){
                    var sort = options.sort[i];
                    query += (i > 0 ? "," : "") + (sort.descending ? '-' : '+') + encodeURIComponent(sort.attribute);
                }
                if(!sortParam){
                    query += ")";
                }
            }
            var results = xhr("GET", {
                url: this.target + (query || ""),
                handleAs: "json",
                headers: headers
            });
            results.total = results.then(function(){
                var range = results.ioArgs.xhr.getResponseHeader("Content-Range");
                return range && (range=range.match(/\/(.*)/)) && +range[1];
            });
            return QueryResults(results);
        },

      mayHaveChildren: function(object)
      {
        // see if it has a children property
        return "items" in object;
      },

      getChildren: function(object, onComplete, onError)
      {
          if(object.id == "_root")
          {
              onComplete(object.items);
              return;
          }

          // retrieve the full copy of the object
          var context = this;
          this.get(this.getIdentity(object)).then(function(fullObject)
          {
              object.items = [];
              dojo.forEach(fullObject[context.childrenProperty], function(item, index){
                  context.append_item(context, object, item);
              });
              onComplete(object.items);
          }, onError);

      },

      getRoot: function(onItem, onError)
      {
        this.root = {
          id : "_root",
          items : [
            {
              caption : 'Тесты',
              id: "/tests",
              items : true
            }
          ]
        }
        onItem(this.root);
      },

      getLabel: function(object)
      {
          return object.caption;
      },

      onError: function(error)
      {
      }

    });

});
